home *** CD-ROM | disk | FTP | other *** search
/ Alles Voor Internet / Tout Pour Internet / alles voor internet.iso / MacInternet™ / Unix / maclayersunixend1.30.shar / 1.30 / macbput.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-16  |  11.9 KB  |  628 lines

  1. /*
  2.  *    macbput.c
  3.  *
  4.  *    This is a modified version of Dave Johnson's macput (see Copyright
  5.  *    below) intended for use with MacLayers v1.20 - v1.30.
  6.  *
  7.  *             Copyright 1993 by Eric C. Rosen
  8.  *             Copyright 1989-1992 by David W. Trissel
  9.  *
  10.  */
  11.  
  12.  
  13. /*
  14.  * (originally macput) -- send file to Macintosh using MacBinary XMODEM protocol
  15.  * Dave Johnson, Brown University Computer Science
  16.  *
  17.  * (c) 1984 Brown University 
  18.  * may be used but not sold without permission
  19.  *
  20.  */
  21.  
  22. /* To compile:    
  23.                   cc -O -o macbput macbput.c
  24.     (Sun 4.2 BSD) cc -O -DSUNBSD42 -o macbput macbput.c
  25.     (System V)    cc -O -DSYSV -o macbput macbput.c
  26.  
  27.    Latest modification 1/93 by Eric Rosen
  28.     to be used with MacLayers v1.20
  29.  
  30.  1. inserted pad byte to be compatible with THINK C's word alignment
  31.     requirements in header; also added identification character as
  32.     temporary hack for version control
  33.  
  34.  2. inserted helpful examples in the usage string when no arguments
  35.     are given
  36.  
  37.  
  38.    Latest modification 4/27/91 by Trissel-
  39.  
  40.  1. Original code was absolutely pathetic recovering from noise on the
  41.     line. In many cases noise on the line would cause program to either
  42.     hang indefinetly or abort instantly. The code to examine responses
  43.     has been enhanced to overcome these limitations.
  44.  
  45.  
  46.    Modification  4/17/91 by Trissel -
  47.  
  48.  1. ??? XMODEM block count not fixed in official MacLayers Release???
  49.     Point 4 below claims that it was, however the code obviously does NOT
  50.     increment the last block count of the data fork if the data fork is
  51.     not an even multiple of 128 bytes in size.
  52.  
  53.    Modifications 10/20/88 by Trissel -
  54.  
  55.  1. General cleanup by removal of unused definitions and headers.
  56.  2. Added #ifdefs to support System V and BSD 4.2 Sun compilation.
  57.  3. Removed ancient Macterminal Beta 0.5X code.
  58.  4. Fixed bad bug where XMODEM block count was not bumped up
  59.     after the first fork transfer.
  60.  
  61.     Dave Trissel
  62.     Motorola Inc.
  63.     ut-sally!oakhill!davet
  64.  
  65.    This code is fundamentally from two earlier programmers:
  66.  
  67.     Jon Hueras
  68.     Symantec/THINK Technologies
  69.     singer@endor.harvard.edu
  70.  
  71.     who added 2-Byte CRC capability to code from:
  72.  
  73.     Dave Johnson
  74.     ddj%brown@csnet-relay.arpa
  75.     Brown University Computer Science
  76.  
  77.    who did the initial MacTerminal 1.1 transfer protocol.
  78. */
  79.  
  80. /* If you have System V define the following: */
  81.     /* #define SYSV */
  82.  
  83. /* Sun BSD 4.2 systems should define the following: */
  84.     /* #define SUNBSD42 */
  85.  
  86. #include <stdio.h>
  87. #include <signal.h>
  88. #ifdef _STRICT_BSD
  89. #define    SIGTYPE int
  90. #else
  91. #define SIGTYPE void
  92. #endif
  93. #include <setjmp.h>
  94. #ifdef SYSV
  95. #include <termio.h>
  96. #else
  97. #include <sgtty.h>
  98. #endif
  99. #include <sys/types.h>
  100. #include <sys/stat.h>
  101.  
  102. #ifdef SUNBSD42
  103. /* RAW is no longer being found on latest Sun system (??) (Trissel) */
  104. #define RAW 0x20
  105. #endif
  106.  
  107. #define RECORDBYTES 132
  108. #define DATABYTES 128
  109. #define NAMEBYTES 64
  110.  
  111. #define RETRIES 10
  112. #define ACKTIMO 10
  113. #define FLUSHTIMO 2
  114.  
  115. #define MAXRECNO 0xff
  116. #define BYTEMASK 0xff
  117.  
  118. #define TMO -1
  119. #define DUP '\000'
  120. #define SOH '\001'
  121. #define EOT '\004'
  122. #define ACK '\006'
  123. #define NAK '\025'
  124. #define CAN '\030'
  125. #define EEF '\032'
  126. #define ESC '\033'
  127.  
  128. #define H_NLENOFF 1
  129. #define H_NAMEOFF 2
  130. /* 65 <-> 80 is the FInfo structure */
  131. #define H_TYPEOFF 65
  132. #define H_AUTHOFF 69
  133.  
  134. #define H_LOCKOFF 81
  135. #define H_DLENOFF 83
  136. #define H_RLENOFF 87
  137. #define H_CTIMOFF 91
  138. #define H_MTIMOFF 95
  139.  
  140. #define H_OLD_DLENOFF 81
  141. #define H_OLD_RLENOFF 85
  142.  
  143. #define TEXT 0
  144. #define DATA 1
  145. #define RSRC 2
  146. #define FULL 3
  147.  
  148. int mode, txtmode;
  149.  
  150. struct macheader {
  151.     char m_name[NAMEBYTES+1];
  152.     char m_type[4];
  153.     char m_author[4];
  154.     long m_datalen;
  155.     long m_rsrclen;
  156.     long m_createtime;
  157.     long m_modifytime;
  158. } mh;
  159.  
  160. struct filenames {
  161.     char f_info[256];
  162.     char f_data[256];
  163.     char f_rsrc[256];
  164. } files;
  165.  
  166. int recno, crc;
  167. char buf[DATABYTES];
  168.  
  169. char usage[] =
  170.     "macbput v1.20\nusage: \"macbput [-rdu] [-t type] [-c creator] [-n name] filename\"\n";
  171.  
  172. main(ac, av)
  173. int    ac;
  174. char **av;
  175. {
  176.     void setup_tty(), find_files(), forge_info(), send_file(), reset_tty();
  177.     int send_sync();
  178.  
  179.     int n;
  180.     char *filename = (char *) NULL;
  181.  
  182.     if (ac == 1) {
  183.         fputs(usage, stderr);
  184.         fputs("Eg:\n\tTo send a binary file:\n", stderr);
  185.         fputs("\n\t\tmacbput -d filename\n", stderr);
  186.         fputs("\n\tTo send a text file:\n", stderr);
  187.         fputs("\n\t\tmacbput -u -t TEXT filename\n", stderr);
  188.         exit(1);
  189.     }
  190.  
  191.     mode = FULL;
  192.     ac--; av++;
  193.     while (ac) {
  194.         if (av[0][0] == '-') {
  195.             switch (av[0][1]) {
  196.             case 'r':
  197.                 mode = RSRC;
  198.                 strncpy(mh.m_type, "????", 4);
  199.                 strncpy(mh.m_author, "????", 4);
  200.                 break;
  201.             case 'u':
  202.                 mode = TEXT;
  203.                 strncpy(mh.m_type, "TEXT", 4);
  204.                 strncpy(mh.m_author, "MACA", 4);
  205.                 break;
  206.             case 'd':
  207.                 mode = DATA;
  208.                 strncpy(mh.m_type, "????", 4);
  209.                 strncpy(mh.m_author, "????", 4);
  210.                 break;
  211.             case 'n':
  212.                 if (ac > 1) {
  213.                     ac--; av++;
  214.                     n = strlen(av[0]);
  215.                     if (n > NAMEBYTES) n = NAMEBYTES;
  216.                     strncpy(mh.m_name, av[0], n);
  217.                     mh.m_name[n] = '\0';
  218.                     break;
  219.                 }
  220.                 else goto bad_usage;
  221.             case 't':
  222.                 if (ac > 1) {
  223.                     ac--; av++;
  224.                     strncpy(mh.m_type, av[0], 4);
  225.                     break;
  226.                 }
  227.                 else goto bad_usage;
  228.             case 'c':
  229.                 if (ac > 1) {
  230.                     ac--; av++;
  231.                     strncpy(mh.m_author, av[0], 4);
  232.                     break;
  233.                 }
  234.                 else goto bad_usage;
  235.             default:
  236. bad_usage:
  237.                 fputs(usage, stderr);
  238.                 exit(1);
  239.             }
  240.         }
  241.         else {
  242.             filename = av[0];
  243.         }
  244.         ac--; av++;
  245.     }
  246.     if (!filename) goto bad_usage;
  247.  
  248.     setup_tty();
  249.     find_files(filename, mode);
  250.     if (mode != FULL)
  251.         forge_info();
  252.  
  253.     if (send_sync()) {
  254.         recno = 1;
  255.         txtmode = 0;
  256.         send_file(files.f_info, 1, '*');
  257.  
  258.         if (mode != FULL)
  259.             unlink(files.f_info);
  260.  
  261.         if (mode == TEXT) txtmode++;
  262.         send_file(files.f_data, 1, '\0');
  263.  
  264.         txtmode = 0;
  265.         send_file(files.f_rsrc, 0, '\0');
  266.     }
  267.     reset_tty();
  268. }
  269.  
  270. void find_files(filename, mode)
  271. char *filename;
  272. int    mode;
  273. {
  274.     SIGTYPE    cleanup();
  275.     int n;
  276.     struct stat stbuf;
  277.  
  278.     sprintf(files.f_data, "%s.data", filename);
  279.     sprintf(files.f_rsrc, "%s.rsrc", filename);
  280.  
  281.     if (mode == FULL) {
  282.         sprintf(files.f_info, "%s.info", filename);
  283.         if (stat(files.f_info, &stbuf) != 0) {
  284.             perror(files.f_info);
  285.             cleanup(-1);
  286.         }
  287.         return;
  288.     }
  289.     else {
  290.         strcpy(files.f_info, "#machdrXXXXXX");
  291.         mktemp(files.f_info);
  292.     }
  293.  
  294.     if (mode == RSRC) {
  295.         strcpy(files.f_data, "/dev/null");
  296.         if (stat(files.f_rsrc, &stbuf) != 0) {
  297.             strcpy(files.f_rsrc, filename);
  298.             if (stat(files.f_rsrc, &stbuf) != 0) {
  299.                 perror(files.f_rsrc);
  300.                 cleanup(-1);
  301.             }
  302.         }
  303.         mh.m_datalen = 0;
  304.         mh.m_rsrclen = stbuf.st_size;
  305.     }
  306.     else {
  307.         strcpy(files.f_rsrc, "/dev/null");
  308.         if (stat(files.f_data, &stbuf) != 0) {
  309.             sprintf(files.f_data, "%s.text", filename);
  310.             if (stat(files.f_data, &stbuf) != 0) {
  311.                 strcpy(files.f_data, filename);
  312.                 if (stat(files.f_data, &stbuf) != 0) {
  313.                     perror(files.f_data);
  314.                     cleanup(-1);
  315.                 }
  316.             }
  317.         }
  318.         mh.m_datalen = stbuf.st_size;
  319.         mh.m_rsrclen = 0;
  320.     }
  321.  
  322.     if (mh.m_name[0] == '\0') {
  323.         n = strlen(filename);
  324.         if (n > NAMEBYTES) n = NAMEBYTES;
  325.         strncpy(mh.m_name, filename, n);
  326.         mh.m_name[n] = '\0';
  327.     }
  328. }
  329.  
  330. void forge_info()
  331. {
  332.     void put4();
  333.     SIGTYPE    cleanup();
  334.  
  335.     int n;
  336.     char *np;
  337.     FILE *fp;
  338.  
  339.     for (np = mh.m_name; *np; np++)
  340.         if (*np == '_') *np = ' ';
  341.  
  342.     buf[H_NLENOFF] = n = np - mh.m_name;
  343.     strncpy(buf + H_NAMEOFF, mh.m_name, n);
  344.     strncpy(buf + H_TYPEOFF, mh.m_type, 4);
  345.     strncpy(buf + H_AUTHOFF, mh.m_author, 4);
  346.     put4(buf + H_DLENOFF, mh.m_datalen);
  347.     put4(buf + H_RLENOFF, mh.m_rsrclen);
  348.     put4(buf + H_CTIMOFF, mh.m_createtime);
  349.     put4(buf + H_MTIMOFF, mh.m_modifytime);
  350.     fp = fopen(files.f_info, "w");
  351.     if (fp == NULL) {
  352.         perror("temp file");
  353.         cleanup(-1);
  354.     }
  355.     fwrite(buf, 1, DATABYTES, fp);
  356.     fclose(fp);
  357. }
  358.  
  359. int send_sync()
  360. {
  361.     void tputc();
  362.     int    tgetc();
  363.     int c;
  364.         
  365.     tputc(ESC);
  366.     tputc('b');
  367.  
  368.     for (;;) {
  369.  
  370.         if ((c = tgetc(ACKTIMO)) == TMO)
  371.         {
  372.             return(0);
  373.         }
  374.  
  375.         if (c == NAK)
  376.         {
  377.             return(1);
  378.         }
  379.  
  380.         if (c == 'C') {
  381.             crc++;
  382.             return(1);
  383.         }
  384.     }
  385. }
  386.  
  387. void send_file(fname, more, id)
  388. char *fname;
  389. int more;
  390. char id;
  391. {
  392.     void send_rec(), tputc();
  393.     int tgetc();
  394.     SIGTYPE cleanup();
  395.  
  396.     register int status, i, n;
  397.     FILE *inf;
  398.  
  399.     inf = fopen(fname, "r");
  400.     if (inf == NULL) {
  401.         perror(fname);
  402.         cleanup(-1);
  403.     }
  404.     for (;;) {
  405.         n = fread(buf, 1, DATABYTES, inf);
  406.         if (id == '*') {
  407.             buf[0] = id;
  408.             for (i=127; i>65; i--)
  409.                 buf[i] = buf[i-1];    /* hack */
  410.         }
  411.         if (n > 0) {
  412.             for (i = 0; i < RETRIES; i++) {
  413.                 send_rec(buf, DATABYTES);
  414.                 status = tgetc(ACKTIMO);
  415.                 if (   status != ACK
  416.                     && status != NAK
  417.                     && status != CAN
  418.                     && status != TMO
  419.                     && status != EOT
  420.                    )
  421.                   {    /* We got unknown response - assume noise on the line
  422.                     ** and flush it. Treat this as a timeout.
  423.                     */
  424.  
  425.                     /* Note: the FLUSHTIMO must be short, otherwise we
  426.                     ** would flush past the (presumed) noise burst and
  427.                     ** possibly miss a CAN which would leave the program
  428.                     ** timing out while the user wonders what happened.
  429.                     ** (Missing anything else is no big deal since we
  430.                     ** are going to retry anyway.)
  431.                     */
  432.                     while ((status=tgetc(FLUSHTIMO)) != TMO)
  433.                         ;
  434.                     /* leave status == TMO */
  435.                   }
  436.  
  437.                 /* exit retry loop if not to resend */
  438.                 if (status == ACK || status == EOT || status == CAN)
  439.                     break;
  440.             } 
  441.             if (status != ACK) {
  442.                 /* we are to terminate */
  443.                 fclose(inf);
  444.                 cleanup(-1);
  445.                 /* NOTREACHED */
  446.             }
  447.  
  448.             /* FIX (d.t.) recno always increments for any block sent out */
  449.             recno++;                /* FIX  d.t. */
  450.             recno &= MAXRECNO;        /* FIX  d.t. */
  451.         }
  452.         if (n < DATABYTES) {
  453.             if (!more) {
  454.                 tputc(EOT);
  455.                 tgetc(ACKTIMO);
  456.             }
  457.             return;
  458.         }
  459.     }
  460. }
  461.  
  462. void send_rec(buf, recsize)
  463. char buf[];
  464. int recsize;
  465. {
  466.     void tputc(), tputrec();
  467.     int calcrc();
  468.  
  469.     int i, cksum = 0;
  470.     char *bp;
  471.  
  472.     if (txtmode || !crc) {
  473.         bp = buf;
  474.         for (i = 0; i < recsize; i++, bp++) {
  475.             if (txtmode && *bp == '\n')
  476.                 *bp = '\r';
  477.             cksum += *bp;
  478.         }
  479.     }
  480.  
  481.     if (crc)
  482.         cksum = calcrc(buf, recsize);
  483.  
  484.     tputc(SOH);
  485.     tputc((char) recno);
  486.     tputc((char) (MAXRECNO - recno));
  487.     tputrec(buf, recsize);
  488.     
  489.     if (crc) {
  490.         tputc((char) (cksum >> 8));
  491.         tputc((char) cksum);
  492.     } else
  493.         tputc((char) cksum);
  494. }
  495.  
  496. static int ttyfd;
  497. static FILE *ttyf;
  498. static jmp_buf timobuf;
  499.  
  500. int tgetc(timeout)
  501. int timeout;
  502. {
  503.     int c;
  504.  
  505.     if (setjmp(timobuf))
  506.         return TMO;
  507.  
  508.     alarm(timeout);
  509.     c = getc(ttyf);
  510.     alarm(0);
  511.  
  512.     if (c == -1)    /* probably hung up or logged off */
  513.         return EOT;
  514.     else
  515.         return c & BYTEMASK;
  516. }
  517.  
  518. void tputrec(buf, count)
  519. char *buf;
  520. int count;
  521. {
  522.     write(ttyfd, buf, count);
  523. }
  524.  
  525. void tputc(c)
  526. char c;
  527. {
  528.     write(ttyfd, &c, 1);
  529. }
  530.  
  531. SIGTYPE timedout()
  532. {
  533. #ifndef NeXT
  534.     signal(SIGALRM, timedout);    /* for pre-4.2 systems */
  535. #endif
  536.     longjmp(timobuf, 1);
  537. }
  538.  
  539. #ifdef SYSV
  540. static struct termio otty, ntty;
  541. #else
  542. static struct sgttyb otty, ntty;
  543. #endif
  544.  
  545. /* should turn messages off */
  546.  
  547. void setup_tty()
  548. {
  549.     SIGTYPE cleanup();
  550.     SIGTYPE timedout();
  551.  
  552.     ttyf = stdin;
  553.     ttyfd = fileno(stdout);
  554. #ifdef SYSV
  555.     ioctl(ttyfd, TCGETA, &otty);        /* get termio info */
  556. #else
  557.     ioctl(ttyfd, TIOCGETP, &otty);
  558. #endif
  559.     signal(SIGHUP, cleanup);
  560.     signal(SIGINT, cleanup);
  561.     signal(SIGQUIT, cleanup);
  562.     signal(SIGTERM, cleanup);
  563.     signal(SIGALRM, timedout);
  564.     ntty = otty;
  565. #ifdef SYSV
  566.     ntty.c_iflag = BRKINT;                /* only interrupt on break */
  567.     ntty.c_oflag = 0;                    /* no output processing */
  568.     ntty.c_cflag |= CS8;                /* 8 bit characters */
  569.     ntty.c_lflag = 0;                    /* no echoing */
  570.     ntty.c_cc[VEOF] = 1;                /* "MIN" minimum chars before input */
  571.     ntty.c_cc[VEOL] = 1;                /* "TIME" maximum .1 secs before feed */
  572.     ioctl(ttyfd, TCSETAF, &ntty);        /* set mode and flush input */
  573. #else
  574.     ntty.sg_flags = RAW;
  575.     ioctl(ttyfd, TIOCSETP, &ntty);
  576. #endif
  577. }
  578.  
  579. void reset_tty()
  580. {
  581.     if (ttyf != NULL) {
  582. #ifdef SYSV
  583.         ioctl(ttyfd, TCSETAF, &otty);    /* reset after output drains */
  584. #else
  585.         sleep (5);                        /* wait for output to drain */
  586.         ioctl(ttyfd, TIOCSETP, &otty);
  587. #endif
  588.     }
  589. }
  590.  
  591. SIGTYPE cleanup(sig)
  592. int sig;
  593. {
  594.     reset_tty();
  595.     exit(sig);
  596. }
  597.  
  598. void put4(bp, value)
  599. char *bp;
  600. long value;
  601. {
  602.     register int i, c;
  603.  
  604.     for (i = 0; i < 4; i++) {
  605.         c = (value >> 24) & BYTEMASK;
  606.         value <<= 8;
  607.         *bp++ = c;
  608.     }
  609. }
  610.  
  611. int calcrc(ptr,    count)
  612. char *ptr;
  613. int count;
  614.     {
  615.         int    crc, i;
  616.  
  617.         crc    = 0;
  618.         while (--count >= 0) {
  619.          crc ^= ((int) *ptr++) << 8;
  620.          for (i = 0; i < 8; ++i)
  621.                  if (crc & 0x8000)
  622.              crc = crc <<    1 ^ 0x1021;
  623.                  else
  624.              crc <<= 1;
  625.          }
  626.         return (crc    & 0xFFFF);
  627.     }
  628.